"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * 基础类型
 */
var isDone = false; // 布尔
var num = 6; // 数字
var str = '6'; // 字符串
var numArr = [1, 3, 4]; // 数组
var strArr = ['1', '6']; // 数组
var x = ['6', 6]; // 元组，当访问越界元素会使用联合类型代替
var Color;
(function (Color) {
    Color[Color["Red"] = 0] = "Red";
    Color[Color["Green"] = 1] = "Green";
    Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {})); // 枚举
var notsure = 5; // any
function warnUser() { } // void
var unuseable = undefined; // 声明void变量没啥用，只能赋值为null、undefined
/**
 * undefined null
 * 如果指定了--strictNullChecks标记，null和undefined只能赋值给void和它们各自
 */
var u = undefined;
var n = null;
var strOrUndefined = '6';
/**
 * never
 * 表示的是那些永不存在的值的类型。
 */
// 返回never的函数必须存在无法达到的终点
function error(msg) {
    throw new Error(msg);
}
// 返回never的函数必须存在无法达到的终点
function infiniteLoop() {
    while (true) {
    }
}
// create({})
// create(3)
/**
 * 类型断言
 */
var someValue = 'this is a string';
var strLength = someValue.length;
/**
 * 接口
 */
/**
 * 类型检查器会查看printLabel的调用。 printLabel有一个参数，
 * 并要求这个对象参数有一个名为label类型为string的属性。
 * 需要注意的是，我们传入的对象参数实际上会包含很多属性，
 * 但是编译器只会检查那些必需的属性是否存在，并且其类型是否匹配。
 * 然而，有些时候TypeScript却并不会这么宽松，我们下面会稍做讲解。
 */
function printLabel(labelledObj) {
    console.log(labelledObj.label);
}
var myObj = { size: 10, label: "Size 10 Object" };
printLabel(myObj);
function printLabel2(labelledObj) {
    console.log(labelledObj.label);
}
var myObj2 = { size: 10, label: "Size 10 Object" };
printLabel2(myObj2);
var p1 = { x: 1, y: 2 };
// 注意：定义的形参名不需要与接口的名字相同
var mySearch = function (source, subString) {
    var res = source.search(subString);
    return res > -1;
};
var Clock = /** @class */ (function () {
    function Clock(h, m) {
    }
    Clock.prototype.setTime = function (d) {
        this.currentTime = d;
    };
    return Clock;
}());
var square = {};
square.color = 'red';
square.sideLength = 3;
function getCounter() {
    var counter = function (start) { };
    counter.interval = 123;
    counter.reset = function () { };
    return counter;
}
var c = getCounter();
c(10);
c.reset();
c.interval = 5;
/**
 * 接口继承类
 * 当接口继承了一个类类型时，它会继承类的成员但不包括其实现。
 * 接口同样会继承到类的private和protected成员。
 * 这意味着当你创建了一个接口继承了一个拥有私有或受保护的成员的类时，
 * 这个接口类型只能被这个类或其子类所实现（implement）
 */
var Control = /** @class */ (function () {
    function Control() {
    }
    return Control;
}());
var Button = /** @class */ (function (_super) {
    __extends(Button, _super);
    function Button() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    Button.prototype.select = function () { };
    return Button;
}(Control));
var TextBox = /** @class */ (function (_super) {
    __extends(TextBox, _super);
    function TextBox() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    TextBox.prototype.select = function () { };
    return TextBox;
}(Control));
// 错误：“Image”类型缺少“state”属性。
// class Image implements SelectableControl {
//     select() { }
// }
var Location = /** @class */ (function () {
    function Location() {
    }
    return Location;
}());
/**
 * 类
 */
var Greeter = /** @class */ (function () {
    function Greeter(msg) {
        this.greeting = msg;
    }
    Greeter.prototype.greet = function () {
        return 'hello, ' + this.greeting;
    };
    return Greeter;
}());
var greeter = new Greeter('world');
// 继承
var Animal = /** @class */ (function () {
    function Animal(theName) {
        this.name = theName;
    }
    Animal.prototype.move = function (distanceInMeters) {
        if (distanceInMeters === void 0) { distanceInMeters = 0; }
        console.log("".concat(this.name, " moved ").concat(distanceInMeters, "m."));
    };
    return Animal;
}());
var Snake = /** @class */ (function (_super) {
    __extends(Snake, _super);
    function Snake(name) {
        return _super.call(this, name) || this;
    }
    Snake.prototype.move = function (distanceInMeters) {
        if (distanceInMeters === void 0) { distanceInMeters = 5; }
        console.log("Slithering...");
        _super.prototype.move.call(this, distanceInMeters);
    };
    return Snake;
}(Animal));
// public 公开的
var Animal2 = /** @class */ (function () {
    function Animal2(name) {
        this.name = name;
    }
    Animal2.prototype.move = function (distanceInMeters) {
        console.log("".concat(this.name, " moved ").concat(distanceInMeters, "m."));
    };
    return Animal2;
}());
// private 不能在声明它的类的外部访问
var Animal3 = /** @class */ (function () {
    function Animal3(name) {
        this.name = name;
    }
    return Animal3;
}());
// new Animal3('cat').name 错误，name是私有的
var R = /** @class */ (function (_super) {
    __extends(R, _super);
    function R() {
        return _super.call(this, 'R') || this;
    }
    return R;
}(Animal3));
// new R().name 错误
// protected 与private类似，但在派生类中仍可访问
var Person = /** @class */ (function () {
    function Person(name) {
        this.name = name;
    }
    return Person;
}());
var Employee = /** @class */ (function (_super) {
    __extends(Employee, _super);
    function Employee(name, department) {
        var _this = _super.call(this, name) || this;
        _this.department = department;
        return _this;
    }
    Employee.prototype.getElevatorPitch = function () {
        return '6';
    };
    return Employee;
}(Person));
// console.log(Employee.name);
var zzd = new Employee('zzd', 'sales');
console.log(zzd.getElevatorPitch());
// console.log(zzd.name);  属性“name”受保护，只能在类“Person”及其子类中访问。
// readonly 只读属性，必须在声明时或构造函数里被初始化
var Octopus = /** @class */ (function () {
    function Octopus(name) {
        this.numberOfLegs = 8;
        this.name = name;
    }
    return Octopus;
}());
var dad = new Octopus('3');
// dad.name = '2'  错误，是只读的
// 存取器
var passcode = '6';
var Employee2 = /** @class */ (function () {
    function Employee2() {
    }
    Object.defineProperty(Employee2.prototype, "fullName", {
        get: function () {
            return this._fullName;
        },
        set: function (newName) {
            if (passcode && passcode == '6') {
                this._fullName = newName;
            }
            else {
                console.log(666);
            }
        },
        enumerable: false,
        configurable: true
    });
    return Employee2;
}());
var employee2 = new Employee2();
employee2.fullName = '6';
// 以上讨论了类的实例属性，仅当类被实例化的时候才会被初始化的属性。
// 接下来看类的静态属性，这些属性存在于类本身而不存在于实例上
var Grid = /** @class */ (function () {
    function Grid() {
    }
    Grid.o = 3;
    return Grid;
}());
// console.log(Grid.o);
// 抽象类
// 抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。 
// 抽象方法的语法与接口方法相似。 两者都是定义方法签名但不包含方法体。
var Animal4 = /** @class */ (function () {
    function Animal4() {
    }
    Animal4.move = function () {
        console.log(6);
    };
    return Animal4;
}());
var Pig = /** @class */ (function (_super) {
    __extends(Pig, _super);
    function Pig() {
        return _super !== null && _super.apply(this, arguments) || this;
    }
    Pig.prototype.makeSound = function () {
        console.log('lululu');
    };
    return Pig;
}(Animal4));
console.log(Pig.move());
/**
 * 函数
 */
// 完整定义
var myAdd = function (x, y) { return x + y; };
// 可选参数：? ， 默认参数=， 默认参数与前面的必须参数或可选参数共享参数类型
// 剩余参数
function buildName(first) {
    var rest = [];
    for (var _i = 1; _i < arguments.length; _i++) {
        rest[_i - 1] = arguments[_i];
    }
}
// this和箭头函数
var deck = {
    suits: ["hearts", "spades", "clubs", "diamonds"],
    cards: Array(52),
    createCardPicker: function () {
        var _this = this;
        // NOTE: the line below is now an arrow function, allowing us to capture 'this' right here
        return function () {
            var pickedCard = Math.floor(Math.random() * 52);
            var pickedSuit = Math.floor(pickedCard / 13);
            return { suit: _this.suits[pickedSuit], card: pickedCard % 13 };
        };
    }
};
var cardPicker = deck.createCardPicker();
var pickedCard = cardPicker();
// alert("card: " + pickedCard.card + " of " + pickedCard.suit)
// 重载 略
/**
 * 泛型
 */
function identify(arg) { return arg; }
var output = identify('zzd');
var output2 = identify('zzd2'); // 会自动推断，更普遍使用
function loggingIdentity(arg) {
    console.log(arg.length); // Array has a .length, so no more error
    return arg;
}
// 泛型类
var GenericNumber = /** @class */ (function () {
    function GenericNumber() {
    }
    return GenericNumber;
}());
var myGenericNumber = new GenericNumber();
myGenericNumber.add = function (x, y) { return x + y; };
myGenericNumber.zeroValue = 0;
console.log(myGenericNumber);
// 创建一个包含 .length属性的接口，使用这个接口和extends关键字来实现约束
function loggingIdentity2(arg) {
    console.log(arg.length); // Now we know it has a .length property, so no more error
    return arg;
}
/**
 * 枚举
 */
// 数字枚举
var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 1] = "Up";
    Direction[Direction["Down"] = 2] = "Down";
    Direction[Direction["Left"] = 3] = "Left";
    Direction[Direction["Right"] = 4] = "Right";
})(Direction || (Direction = {}));
// 字符串枚举
var Direction2;
(function (Direction2) {
    Direction2["Up"] = "UP";
    Direction2["Down"] = "DOWN";
    Direction2["Left"] = "LEFT";
    Direction2["Right"] = "RIGHT";
})(Direction2 || (Direction2 = {}));
var x2;
var y = { name: '6', location: '6' };
x2 = y;
/**
 * 高级类型
 */
// 1. 交叉类型
function extend(first, second) {
    var result = {};
    for (var id in first) {
        result[id] = first[id];
    }
    for (var id in second) {
        if (!result.hasOwnProperty(id)) {
            result[id] = second[id];
        }
    }
    return result;
}
var Person2 = /** @class */ (function () {
    function Person2(name) {
        this.name = name;
    }
    return Person2;
}());
var ConsoleLogger = /** @class */ (function () {
    function ConsoleLogger() {
    }
    ConsoleLogger.prototype.log = function () {
        //...
    };
    return ConsoleLogger;
}());
var jim = extend(new Person2('jim'), new ConsoleLogger());
var n2 = jim.name;
jim.log();
